<?php

/**
 * Class Places
 */
class Places extends ControllerAbtract
{
    /**
     *
     */
    const STATUS_OK = 'OK';
    /**
     *
     */
    const STATUS_ZERO_RESULTS = 'ZERO_RESULTS';

    /**
     * @var
     */
    protected $action;
    /**
     * @var string
     */
    protected $api_key = 'AIzaSyBnV5Bs1Y-isQoxuXbQ3g-91YnJG_EuSdE';
    /**
     * @var string
     */
    protected $api_url = 'https://maps.googleapis.com/maps/api/place/textsearch/';
    /**
     * @var string
     */
    protected $api_result_format = 'json';
    /**
     * @var array
     */
    protected $required_params = array(
        'query'
    );
    /**
     * @var int
     */
    protected $next_page_timer = 2000000; // 2 sec
    /**
     * @var bool
     */
    protected $get_all = false;

    /**
     * @param $params
     */
    protected function init($params)
    {
        $this->action = array_shift($params);
        $this->get_all = $this->Request->getGetAll(false);
    }

    /**
     * @throws Exception
     */
    public function process()
    {
        if (!method_exists($this, $this->action)) {
            throw new Exception("Call to undefined action: {$this->action}");
        }
        if (!$this->Request->validate($this->required_params)) {
            throw new Exception("Request is invalid: " . print_r($this->Request->getAll(), true));
        }
        $this->{$this->action}();
    }

    /**
     * @throws Exception
     */
    protected function search()
    {
        if (!$query = $this->Request->getQuery()) {
            throw new Exception("Empty query");
        }

        $query_key = md5($query);
        if (!$result = CacheFacade::getInstance()->get(md5($query))) {
            $response = $this->makeRequest(array('query' => $query));
            $result = $this->processResponse($response);
            $result = $this->makeResonse($result);
            CacheFacade::getInstance()->set($query_key, $result);
        }
        $this->render($result);
    }

    /**
     * @param $result
     */
    protected function render($result)
    {
        header('Content-type: application/json');
        echo $result;
    }

    /**
     * @param $params
     * @return mixed
     * @throws Exception
     */
    protected function makeRequest($params)
    {
        $url = $this->api_url . $this->api_result_format . '?' . $this->makeRequestStr($params);
        $result = $this->makeCurlRequest($url);
        if (!$response = json_decode($result, true)) {
            throw new Exception("Unexpected result: " . $result);
        }

        return $response;
    }

    /**
     * @param $result
     * @return string
     */
    protected function makeResonse($result)
    {
        return json_encode($result);
    }

    /**
     * @param $response
     * @return array
     * @throws Exception
     */
    protected function processResponse($response)
    {
        $result = array();
        switch ($response['status']) {
            case self::STATUS_ZERO_RESULTS:
                break;
            case self::STATUS_OK:
                foreach ($response['results'] as $place) {
                    $result[] = array(
                        'name' => $place['name'],
                        'address' => $place['formatted_address'],
                    );
                    if ($this->get_all && !empty($response['next_page_token'])) {
                        usleep($this->next_page_timer);
                        $response = $this->makeRequest(array('pagetoken' => $response['next_page_token']));
                        $result = array_merge($result, $this->processResponse($response));
                    }
                }
                break;
            default:
                throw new Exception("Failed response: " . print_r($response, true));
                break;
        }
        return $result;
    }

    /**
     * @param $params
     * @return mixed
     */
    protected function makeRequestStr($params)
    {
        $arr = array(
            'key' => $this->api_key,
            'sensor' => 'false'
        ) + $params;
        $str = $this->Request->arr2str($arr);
        return $str;
    }

    /**
     * @param $url
     * @return mixed
     */
    protected function makeCurlRequest($url)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
        curl_setopt($ch, CURLOPT_TIMEOUT, 2);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }
}